package info.batcloud.fanli.core.service.impl;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import info.batcloud.fanli.core.alipay.domain.NotifyParam;
import info.batcloud.fanli.core.alipay.domain.TradeStatus;
import info.batcloud.fanli.core.dto.OrderForPay;
import info.batcloud.fanli.core.config.AlipayConfig;
import info.batcloud.fanli.core.entity.AlipayPayment;
import info.batcloud.fanli.core.entity.IntegralPayment;
import info.batcloud.fanli.core.entity.Order;
import info.batcloud.fanli.core.enums.OrderPayType;
import info.batcloud.fanli.core.repository.AlipayPaymentRepository;
import info.batcloud.fanli.core.repository.IntegralPaymentRepository;
import info.batcloud.fanli.core.repository.OrderRepository;
import info.batcloud.fanli.core.service.IntegralService;
import info.batcloud.fanli.core.service.OrderService;
import info.batcloud.fanli.core.service.WalletService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.inject.Inject;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
public class OrderServiceImpl implements OrderService {

    private static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);

    @Inject
    private OrderRepository orderRepository;

    @Inject
    private WalletService walletService;

    private Map<Class, OrderHandler> orderHandlerMap = new HashMap<>();

    @Inject
    private IntegralService integralService;

    @Inject
    private IntegralPaymentRepository integralPaymentRepository;

    @Inject
    private AlipayPaymentRepository alipayPaymentRepository;

    @Inject
    private AlipayConfig alipayConfig;

    @Override
    @Transactional
    public IntegralPayResult payByIntegral(long id) {
        IntegralPayResult result = new IntegralPayResult();
        Order order = orderRepository.findOne(id);
        OrderHandler orderHandler = orderHandlerMap.get(order.getClass());
        CheckPayResult checkPayResult = orderHandler.checkPay(order);
        if (!checkPayResult.isSuccess()) {
            result.setSuccess(false);
            result.setCode(checkPayResult.getCode(), checkPayResult.getArgs());
            return result;
        }
        float integral = integralService.toIntegral(order.getTotalFee());
        WalletService.WalletConsumeResult consumeResult =
                walletService.consumeIntegral(order.getUserId(), integral, order.walletFlowDetailType(), order.getId() + "");
        if (consumeResult.isSuccess()) {
            //如果积分扣除成功，那么生成payment信息 这里支付成功
            order.setPayType(OrderPayType.INTEGRAL);
            order.setPaidIntegral(integral);
            order.setUpdateTime(new Date());
            order.setPayTime(new Date());
            //保存payment信息
            IntegralPayment payment = new IntegralPayment();
            payment.setIntegral(integral);
            payment.setCreateTime(new Date());
            payment.setOrderId(id);
            payment.setEquivalentMoney(order.getTotalFee());
            payment.setUserId(order.getUserId());
            integralPaymentRepository.save(payment);
        }
        PayResult payResult = new PayResult();
        payResult.setSuccess(consumeResult.isSuccess());
        payResult.setOrderPayType(OrderPayType.INTEGRAL);
        orderHandler.handlePayResult(order, payResult);
        orderRepository.save(order);
        result.setCode(consumeResult.getCode(), consumeResult.getArgs());
        result.setSuccess(consumeResult.isSuccess());
        return result;
    }

    @Override
    public OrderForPay findPayInfo(long id) {
        Order order = orderRepository.findOne(id);
        OrderHandler handler = orderHandlerMap.get(order.getClass());
        OrderForPay dto = new OrderForPay();
        dto.setContent(handler.getContent(order));
        dto.setTotalFee(order.getTotalFee());
        dto.setCreateTime(order.getCreateTime());
        dto.setStatusTitle(handler.getStatusTitle(order));
        dto.setCanPay(handler.isCanPay(order));
        return dto;
    }


    @Override
    public <T extends Order> void registerOrderHandler(Class<T> orderClazz, OrderHandler<T> orderHandler) {
        orderHandlerMap.put(orderClazz, orderHandler);
    }

    @Override
    public AlipayTradeAppPayResponse appAlipay(long id) throws AlipayApiException {
        AlipayClient alipayClient = new DefaultAlipayClient(alipayConfig.getServerUrl(), alipayConfig.getAppId(), alipayConfig.getPrivateKey(),
                "json", "utf8", alipayConfig.getAlipayPublicKey(), alipayConfig.getSignType());
        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        //SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        Order order = orderRepository.findOne(id);
        OrderHandler handler = orderHandlerMap.get(order.getClass());
        model.setBody(handler.getContent(order));
        model.setSubject(handler.getTitle(order));
        model.setOutTradeNo(order.getId() + "");
        model.setTimeoutExpress("30m");
        model.setTotalAmount(order.getTotalFee() + "");
        model.setProductCode("QUICK_MSECURITY_PAY");
        request.setBizModel(model);
        request.setNotifyUrl(alipayConfig.getNotifyUrl());
        //这里和普通的接口调用不同，使用的是sdkExecute
        AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
        return response;
    }

    @Override
    @Transactional
    public boolean handleAlipayNotify(NotifyParam param) throws AlipayApiException {
        logger.info("处理支付宝支付异步通知");
        if (!param.getAppId().equals(alipayConfig.getAppId())) {
            logger.info("支付回掉的appId与系统不一致，" + param.getAppId() + " -> " + alipayConfig.getAppId());
            return false;
        }
        if (param.getTradeStatus() == TradeStatus.TRADE_SUCCESS) {
            //签名验证
            Map<String, String> checkParams = new HashMap<>(param.getRawMap());
            checkParams.remove("sign_type");
            boolean signVerified = AlipaySignature.rsaCheckV2(checkParams, alipayConfig.getAlipayPublicKey(), param.getCharset(), alipayConfig.getSignType()); //调用SDK验证签名
            if (!signVerified) {
                logger.info("支付宝支付回掉通知签名验证失败");
                return false;
            }
            long orderId = Long.valueOf(param.getOutTradeNo());
            Order order = orderRepository.findOne(orderId);
            //保存payment信息
            AlipayPayment payment = new AlipayPayment();
            BeanUtils.copyProperties(param, payment);
            payment.setUserId(order.getUserId());
            payment.setCreateTime(new Date());
            payment.setOrderId(orderId);
            alipayPaymentRepository.save(payment);
            PayParam payParam = new PayParam();
            payParam.setOrderId(orderId);
            payParam.setTotalAmount(param.getTotalAmount());
            payParam.setPayType(OrderPayType.ALIPAY);
            return payOrder(order, payParam);
        }
        return false;
    }

    @Override
    public boolean payOrder(PayParam payParam) {
        Order order = orderRepository.findOne(payParam.getOrderId());
        return payOrder(order, payParam);
    }

    private boolean payOrder(Order order, PayParam payParam) {
        OrderHandler orderHandler = orderHandlerMap.get(order.getClass());
        CheckPayResult checkPayResult = orderHandler.checkPay(order);
        if (!checkPayResult.isSuccess()) {
            logger.info("订单检查支付失败");
            return false;
        }
        if (payParam.getTotalAmount() < order.getTotalFee()) {
            logger.info("支付的金额与订单的金额不一致，" + payParam.getTotalAmount() + " -> " + order.getTotalFee());
            return false;
        }
        order.setPayType(payParam.getPayType());
        order.setPaidFee(payParam.getTotalAmount());
        order.setUpdateTime(new Date());
        order.setPayTime(new Date());
        PayResult payResult = new PayResult();
        payResult.setSuccess(true);
        payResult.setOrderPayType(OrderPayType.ALIPAY);
        orderHandler.handlePayResult(order, payResult);
        orderRepository.save(order);
        return true;
    }


}
